<template>
  <div class="select-wrap" :style="{ width: props.width }">
    <n-select
      ref="selectInstRef"
      :placeholder="placeholder"
      v-model:value="searchValue"
      v-bind="$attrs"
      :loading="searchLoading"
      :options="childList"
      :label-field="props.label"
      :value-field="props.value"
      :disabled="props.disabled"
      :onUpdate:value="updateFn"
      :render-option="renderOptionFn"
      @scroll="handleScrollFn"
      @search="handleSearchFn"
      @focus="handleFocusFn"
    />
  </div>
</template>

<script lang="ts" setup>
  import { onMounted, ref, h, VNode } from 'vue';
  import { NSelect, NTooltip, SelectOption } from 'naive-ui';
  import { t } from '@/i18n';
  import { cloneDeep } from 'lodash-es';
  type Props = {
    label: string; // 选项 label 的字段名
    value: string; // 选项 value 的字段名
    codeValue?: string; // 自定义显示第一个label字段
    nameValue?: string; //自定义显示第二个value字段
    otherValue?: string; // 自定义显示第三个字段
    onlyName?: boolean; // 只显示label不以“name(code)”方式显示
    getRemoteList: any; // 请求数据方法
    remoteParams?: any; // 传参
    disabled?: boolean; // 是否禁用
    width: string; // 宽度
    formValue: any; // 父组件传过来的值
    searchKey?: string; // 搜索值
    placeholder?: string; // 占位符
    searchValueList?: string;
    pageSize?: number; // 页数

    isEditTable?: boolean;
    isFilterList?: boolean;
    filterList?: any;
    filterKey?: any;
    table?: any;
    isNeedValid?: boolean; // 页数
    isRequestSearch?: boolean; // 是否要远程搜索
    // resetMenuOnOptionsChange: boolean; //是否在选项变化时重置菜单状态，例如滚动状态
    // remote: boolean; //是否要异步获取选项
    listCallback?: Fn;
  };

  const props = withDefaults(defineProps<Props>(), {
    label: () => '',
    value: () => '',
    getRemoteList: () => {},
    remoteParams: () => {
      return {};
    },
    disabled: () => false,
    codeValue: () => '',
    nameValue: () => '',
    width: () => '300px',
    formValue: () => null,
    searchKey: () => '',
    searchValueList: () => '',
    // resetMenuOnOptionsChange: () => true,
    // remote: () => false,
    placeholder: () => t('common.form.plSelect'),
    otherValue: () => '',
    onlyName: () => false,
    pageSize: () => 10,
    isEditTable: () => false,
    isFilterList: () => false,
    filterList: () => [],
    filterKey: () => null,
    table: () => null,
    isNeedValid: true,
    c: false,
    listCallback: () => {},
  });
  const emit = defineEmits(['changeSelect']);

  const placeholder = ref(t('common.form.plSelect'));

  onMounted(() => {
    if (props.formValue) {
      searchValue.value = props.formValue;
    } else {
      searchValue.value = null;
    }
  });

  const childList: any = ref([]);
  const allList: any = ref([]);
  const searchParamsList: any = ref('');
  const searchLoading = ref(false);
  const curPageNum = ref<number>(1);
  const searchValue: any = ref(null);
  const pageNum = ref<number>(0);
  const selectInstRef: any = ref(null);
  const updateFn = (e) => {
    console.log(e);
    const isArray = Array.isArray(e);
    let equipItem;
    if (!isArray) {
      equipItem = childList.value.find((item) => item[props.value] === e);
    } else {
      equipItem = [];
      e.map((a) => {
        childList.value.map((b) => {
          b[props.value] === a && equipItem.push(b);
        });
      });
    }

    emit('changeSelect', equipItem);

    if (!searchValue.value) {
      childList.value = [];
      setTimeout(() => {
        let searchParams = {
          ...props.remoteParams,
          pageNum: 1,
        };
        console.log('searchKey', props.searchKey);

        if (props.searchValueList) {
          searchParamsList.value = '';
          getList(searchParamsList.value);
        } else {
          const searchKeys = props.searchKey.split('.');
          if (searchKeys.length === 1) {
            searchParams[searchKeys[0]] = null;
          } else {
            searchParams[searchKeys[0]] = {
              ...props.remoteParams[searchKeys[0]],
              [searchKeys[1]]: null,
            };
          }
          getList(searchParams);
        }
      }, 600);
    }
    // if (props.isNeedValid) {
    //   setTimeout(() => {
    //     selectInstRef.value?.blur();
    //   }, 100);
    // }
  };

  const renderOptionFn = ({ node, option }: { node: VNode; option: SelectOption }) => {
    setNodeFn(node.children, option);

    return h(
      NTooltip,
      {
        placement: 'right-end',
        'show-arrow': false,
        raw: true,
        overlap: true,
        delay: 500,
        animated: false,
        'content-style': {
          fontSize: '12px',
          color: '#333',
          backgroundColor: '#FFF',
          padding: '3px 10px',
          border: '1px solid #333',
          position: 'absolute',
          width: 'max-content',
          // bottom: '20%',
          left: '-50px',
        },
      },
      {
        trigger: () => node,
        default: () => getLabelFn(option),
      }
    );
  };

  const getLabelFn = (option: SelectOption) => {
    const { label, value, codeValue, nameValue, otherValue, onlyName } = props;
    return onlyName
      ? option[codeValue || label]
      : `${option[codeValue || label]}(${option[nameValue || value]}${
          otherValue ? `,${option[otherValue] || '-'}` : ''
        })`;
  };

  const setNodeFn = (children: any, option: SelectOption) => {
    if (children && children.length) {
      for (let item of children) {
        if (item) {
          if (typeof item === 'string') {
            item = getLabelFn(option);
          } else if (typeof item === 'object') {
            if (item.children) {
              if (typeof item.children === 'string') {
                item.children = getLabelFn(option);
              } else if (item.children.length) {
                setNodeFn(item.children, option);
              }
            }
          }
        }
      }
    }
  };

  const handleScrollFn = async (e: Event) => {
    const currentTarget = e.currentTarget as HTMLElement;
    if (currentTarget.scrollTop + currentTarget.offsetHeight >= currentTarget.scrollHeight) {
      curPageNum.value++;
      if (curPageNum.value > pageNum.value) return;
      getList({
        ...props.remoteParams,
        pageNum: curPageNum.value,
      });
    }
  };

  // const handleBlurFn = () => {
  //   childList.value = allList.value;
  // };

  // const handleBlurFn = async () => {
  //   let searchParams = {
  //     ...props.remoteParams,
  //     pageNum: 1,
  //   };
  //   console.log('searchKey', props.searchKey);

  //   if (props.searchValueList) {
  //     searchParamsList.value = '';
  //     getList(searchParamsList.value);
  //   } else {
  //     const searchKeys = props.searchKey.split('.');
  //     if (searchKeys.length === 1) {
  //       searchParams[searchKeys[0]] = null;
  //     } else {
  //       searchParams[searchKeys[0]] = {
  //         ...props.remoteParams[searchKeys[0]],
  //         [searchKeys[1]]: null,
  //       };
  //     }
  //     getList(searchParams);
  //   }
  // };

  // const updateShowFn = () => {
  //   setTimeout(() => {
  //     childList.value = allList.value;
  //   }, 1000);
  // };

  const handleSearchFn = async (query: string) => {
    if (query.length > 250) {
      return;
    }
    searchValue.value = query ? query : null;
    searchParamsList.value = query;
    let searchParams = {
      ...props.remoteParams,
      pageNum: 1,
    };
    console.log('query' + query);

    if (props.isRequestSearch) {
      console.log('search', props.isRequestSearch);
      if (query) {
        childList.value = (() => {
          return allList.value.filter(
            (e) =>
              e[props.codeValue].toLowerCase().indexOf(query.toLowerCase()) != -1 ||
              e[props.nameValue].toLowerCase().indexOf(query.toLowerCase()) != -1
          );
        })();
      } else {
        childList.value = allList.value;
        placeholder.value = t('common.form.plSelect');
        // let placeh = document.getElementsByClassName('.n-base-selection-overlay__wrapper');

        // placeh.innerHTML = t('common.form.plSelect');
        // console.log(placeholder.value);
      }
    } else {
      if (props.searchValueList) {
        getList(searchParamsList.value);
      } else {
        const searchKeys = props.searchKey.split('.');
        if (searchKeys.length === 1) {
          searchParams[searchKeys[0]] = query;
        } else {
          searchParams[searchKeys[0]] = {
            ...props.remoteParams[searchKeys[0]],
            [searchKeys[1]]: query,
          };
        }
        getList(searchParams);
      }
    }
  };

  const handleFocusFn = async () => {
    searchValue.value = props.formValue;

    let searchParams = {
      ...props.remoteParams,
      pageNum: 1,
    };
    console.log('searchKey', props.searchKey);

    if (props.searchValueList) {
      searchParamsList.value = '';
      getList(searchParamsList.value);
    } else {
      const searchKeys = props.searchKey.split('.');
      if (searchKeys.length === 1) {
        searchParams[searchKeys[0]] = null;
      } else {
        searchParams[searchKeys[0]] = {
          ...props.remoteParams[searchKeys[0]],
          [searchKeys[1]]: null,
        };
      }
      getList(searchParams);
    }
  };

  const selectCheckFn = async (val: string) => {
    searchValue.value = val;
    // console.log(searchValue.value);
  };

  const setListFn = async (rowList: any = []) => {
    const {
      isFilterList = false,
      filterList = [],
      filterKey = null,
      isEditTable = false,
      table = null,
    } = props;

    if (isFilterList && rowList && rowList.length && filterKey) {
      let newFilterList = [];

      if (filterList.length) {
        newFilterList = filterList;
      } else if (isEditTable && table) {
        newFilterList = cloneDeep(table.getEditTableDataFn() || []);
      }

      if (newFilterList && newFilterList.length) {
        const list: any = [];

        for (const item of rowList) {
          const isPush = newFilterList.every((fItem) => {
            if (Array.isArray(filterKey)) {
              const pass: any = [];
              let idx = 0;
              while (idx < filterKey.length) {
                pass.push(fItem[filterKey[idx]] === item[filterKey[idx]]);
                idx++;
              }
              if (pass.filter((e) => e).length === filterKey.length) {
                return false;
              }
            } else {
              if (fItem[filterKey] === item[filterKey]) {
                return false;
              }
            }

            return true;
          });

          if (isPush) {
            list.push(item);
          }
        }

        return list;
      }
    }

    return rowList;
  };

  const getList = async (params: any) => {
    try {
      searchLoading.value = true;
      let reqParams;
      if (props.remoteParams) {
        reqParams = params || props.remoteParams;
        if (reqParams?.pageNum === 1) {
          childList.value = [];
        }
      } else {
        reqParams = params || '';
        childList.value = [];
      }
      // console.log(params);

      await props
        .getRemoteList(reqParams)
        .then(async ({ row, total }) => {
          console.log('listCallback', props.listCallback);
          if (props.listCallback) {
            row = await props.listCallback(row);
          }
          row = row.map((rowItem) => {
            if (typeof rowItem === 'string') {
              return {
                [props.codeValue || props.value]: rowItem,
              };
            } else {
              return rowItem;
            }
          });

          if (row?.length) {
            const list = [...(reqParams.pageNum === 1 ? [] : unref(childList)), ...row];

            const newList = await setListFn(list);

            childList.value = newList;
            allList.value = newList;

            searchValue.value = props.formValue || null;
          }
          if (props.remoteParams) {
            const { pageSize } = props.remoteParams;

            pageNum.value = Math.ceil(total / (pageSize ? pageSize : props.pageSize));
          }
        })
        .finally(() => {
          searchLoading.value = false;
        });
    } catch (error) {
      console.log('search error:', error);
    }
  };

  onMounted(() => {
    nextTick(() => {
      getList(props.remoteParams);
    });
  });

  watch(
    () => props.formValue,
    () => {
      // console.log(props.formValue);

      searchValue.value = props.formValue ? props.formValue : null;
    }
  );
  defineExpose({ getList, selectCheckFn });
</script>
<style lang="less" scoped>
  // .select-wrap {
  //   width: 300px;
  // }
  :deep(.n-base-selection-tag-wrapper) {
    max-width: calc(100% - 37px) !important;
  }
</style>
